package com.wanwu.channel.remote.wxpay.http;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.wanwu.channel.common.constant.C;
import com.wanwu.channel.common.enums.ExceptionEnum;
import com.wanwu.channel.common.enums.TradeStatusEnum;
import com.wanwu.channel.common.exception.SystemException;
import com.wanwu.channel.common.util.LogUtil;
import com.wanwu.channel.common.util.TrueFalse;
import com.wanwu.channel.common.util.UtilDate;
import com.wanwu.channel.common.util.XmlUtil;
import com.wanwu.channel.dao.entity.ChannelMerchantInfoEntity;
import com.wanwu.channel.remote.wxpay.config.WeixinGlobalConfig;
import com.wanwu.channel.remote.wxpay.util.WXPayUtil;
import com.wanwu.channel.remote.wxpay.util.WechatSignUtil;
import com.wanwu.channel.service.strategy.domain.CustomsDeclare;
import com.wanwu.channel.service.strategy.domain.QueryApplyClearanceStrategyResponse;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.http.Consts;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.net.ssl.*;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName WechatHttp
 * @Description 微信http类
 * @Author husheng
 * @Date 2020-01-04 14:29
 */
@Component
public class WechatHttp {

    private static Logger logger = LoggerFactory.getLogger(WechatHttp.class);

    private static final String DEFAULT_ENCODING = "UTF-8";

    /**
     * 接口请求超时时间
     */
    private static final int REQUEST_TIME = 5 * 1000;

    private static ConcurrentHashMap<String, SSLConnectionSocketFactory> sslsfMap = new ConcurrentHashMap<>();

    @Resource
    private WeixinGlobalConfig weixinGlobalConfig;

    /**
     *
     */
    public enum InterEnum {
        PREPAY("预下单"),
        PAY_QUERY("订单查询"),
        CLOSE_ORDER("关闭订单"),
        APPLY_REFUND("退款申请"),
        QUERY_REFUND("退款查询"),
        DECLARE_CUSTOMS("清关"),
        DECLARE_CUSTOMS_QUERY("清关查询"),
        DECLARE_CUSTOMS_RESEND("清关重推"),
        ;

        private String interName;

        InterEnum(String interName) {
            this.interName = interName;
        }

        public String getInterName() {
            return interName;
        }

    }

    /**
     * APP直连预下单预下单
     *
     * @param prepayReq
     * @return
     */
    public PrepayResp prepay(PrepayReq prepayReq) {
        prepayReq.setNonceStr(WXPayUtil.generateNonceStr());
        return doRealDealGetBean(prepayReq, PrepayResp.class, InterEnum.PREPAY);
    }

    /**
     * 订单结果查询
     *
     * @param payQueryReq
     * @return
     */
    public PayQueryResp payQuery(PayQueryReq payQueryReq) {
        payQueryReq.setNonceStr(WXPayUtil.generateNonceStr());
        return doRealDealGetBean(payQueryReq, PayQueryResp.class, InterEnum.PAY_QUERY);
    }

    /**
     * 退款申请
     *
     * @param applyRefundReq
     * @return
     */
    public ApplyRefundResp applyRefund(ApplyRefundReq applyRefundReq) {
        applyRefundReq.setNonceStr(WXPayUtil.generateNonceStr());
        return doRealDealGetBean(applyRefundReq, ApplyRefundResp.class, applyRefundReq.getMchId(), InterEnum.APPLY_REFUND);
    }

    /**
     * 关单
     *
     * @param closeOrderReq
     * @return
     */
    public CloseOrderResp closeOrder(CloseOrderReq closeOrderReq) {
        closeOrderReq.setNonceStr(WXPayUtil.generateNonceStr());
        return doRealDealGetBean(closeOrderReq, CloseOrderResp.class, InterEnum.CLOSE_ORDER);
    }

    /**
     * 退款查询
     *
     * @param queryRefundReq
     * @return
     */
    public QueryRefundResp queryRefund(QueryRefundReq queryRefundReq) {
        queryRefundReq.setNonceStr(WXPayUtil.generateNonceStr());
        return doRealDealGetBean(queryRefundReq, QueryRefundResp.class, queryRefundReq.getMchId(), InterEnum.QUERY_REFUND);

    }

    /**
     * 清关
     */
    public DeclareCustomsResp declareCustoms(DeclareCustomsReq declareCustomsReq) {
        return doRealDealGetBean(declareCustomsReq, DeclareCustomsResp.class, InterEnum.DECLARE_CUSTOMS);
    }

//    /**
//     * 清关查询
//     */
//    public QueryApplyClearanceStrategyResponse declareCustomsQry(DeclareCustomsQryReq declareCustomsQryReq) {
//        Map<String, String> resultMap = doRealDealGetMap(declareCustomsQryReq, InterEnum.DECLARE_CUSTOMS_QUERY);
//        return convertDeclareConstomsQryResp(resultMap);
//    }

    /**
     * 清关查询
     * @param req
     * @return
     */
    public DeclareCustomsQryResp declareCustomsQry(DeclareCustomsQryReq req) {
        Map<String, String> map = doRealDealGetMap(req, InterEnum.DECLARE_CUSTOMS_QUERY);
        DeclareCustomsQryResp resp = new DeclareCustomsQryResp();
        resp.setReturnCode(map.get("return_code"));
        resp.setReturnMsg(map.get("return_msg"));
        resp.setSign(map.get("sign"));
        resp.setAppId(map.get("appid"));
        resp.setMchId(map.get("mch_id"));
        resp.setResultCode(map.get("result_code"));
        resp.setErrCode(map.get("err_code"));
        resp.setErrCodeDesc(map.get("err_code_des"));
        resp.setTransactionId(map.get("transaction_id"));
        resp.setCount(Integer.parseInt(map.get("count")));

        List<DeclareCustomsQryInfo> resultList = new ArrayList<>();
        for (int i = 0; i < resp.getCount(); i++) {
            DeclareCustomsQryInfo qryInfo = new DeclareCustomsQryInfo();
            qryInfo.setIndex(i);
            qryInfo.setSubOrderNo(map.get("sub_order_no_" + i));
            qryInfo.setSubOrderId(map.get("sub_order_id_" + i));
            qryInfo.setMchCustomsNo(map.get("mch_customs_no_" + i));
            qryInfo.setCustoms(map.get("customs_" + i));
            qryInfo.setFeeType(map.get("fee_type_" + i));
            qryInfo.setOrderFee(Integer.parseInt(map.get("order_fee_" + i)));
            qryInfo.setDuty(Integer.parseInt(map.get("duty_" + i)));
            qryInfo.setTransportFee(Integer.parseInt(map.get("transport_fee_" + i)));
            qryInfo.setProductFee(Integer.parseInt(map.get("product_fee_" + i)));
            qryInfo.setState(map.get("state_" + i));
            qryInfo.setExplanation(map.get("explanation_" + i));
            qryInfo.setModifyTime(map.get("modify_time_" + i));
            qryInfo.setCertCheckResult(map.get("cert_check_result_" + i));
            qryInfo.setVerifyDepartment(map.get("verify_department_" + i));
            qryInfo.setVerifyDepartmentTradeId(map.get("verify_department_trade_id_" + i));
            resultList.add(qryInfo);
        }
        resp.setResultList(resultList);
        return resp;
    }

    /**
     * 清关重推
     */
    public DeclareCustomsResendResp declareCustomsResend(DeclareCustomsResendReq resendReq) {
        return doRealDealGetBean(resendReq, DeclareCustomsResendResp.class, InterEnum.DECLARE_CUSTOMS_RESEND);
    }


    private QueryApplyClearanceStrategyResponse convertDeclareConstomsQryResp(Map<String, String> resultMap) {
        QueryApplyClearanceStrategyResponse resp = new QueryApplyClearanceStrategyResponse();
        if (resultMap != null) {
            if (TrueFalse.UPPER_SUCCESS.equals(resultMap.get("return_code"))) {
                resp.setSuccess(Boolean.TRUE);
                if (TrueFalse.UPPER_SUCCESS.equals(resultMap.get("result_code"))) {
                    int count = Integer.parseInt(resultMap.get("count"));
                    resp.setCount(count);
                    List<CustomsDeclare> customsDeclareList = new ArrayList<>();
                    for (int i = 0; i < count; i++) {
                        CustomsDeclare cd = new CustomsDeclare();
                        cd.setTradeNo(resultMap.get("transaction_id"));
                        cd.setSubOrderNo(resultMap.get("sub_order_no_" + i));
                        cd.setWeixinSubOrderNo(resultMap.get("sub_order_id_" + i));
                        cd.setMerchantCustomsNo(resultMap.get("mch_customs_no_" + i));
                        cd.setCustomsPlace(resultMap.get("customs_" + i));
                        cd.setCurrency(resultMap.get("fee_type_" + i));
                        cd.setSubOrderFee(Integer.parseInt(resultMap.get("order_fee_" + i)));
                        cd.setDuty(Integer.parseInt(resultMap.get("duty_" + i)));
                        cd.setTransportFee(Integer.parseInt(resultMap.get("transport_fee_" + i)));
                        cd.setProductFee(Integer.parseInt(resultMap.get("product_fee_" + i)));
                        cd.setApplyClearanceResultStatus(resultMap.get("state_" + i));
                        cd.setCustomsInfo(resultMap.get("explanation_" + i));
                        cd.setLastModifyTime(UtilDate.parseDateTimeLong(resultMap.get("modify_time_" + i)));
                        cd.setIdentityCheck(resultMap.get("cert_check_result_" + i));
                        cd.setVerDept(resultMap.get("verify_department"));
                        cd.setPayTransactionId(resultMap.get("verify_department_trade_id"));
                        customsDeclareList.add(cd);
                    }
                    resp.setDeclareList(customsDeclareList);
                } else {
                    resp.setErrorCode(resultMap.get("err_code"));
                    resp.setErrorMsg(resultMap.get("err_code_des"));
                }
            } else {
                resp.setSuccess(Boolean.FALSE);
                resp.setErrorMsg(resultMap.get("return_msg"));
                resp.setErrorCode(resultMap.get("return_code"));
            }
        }
        return resp;
    }



    /**
     * 调用对应的接口,返回bean对象
     *
     * @param request
     * @param cla
     * @param interName
     * @param <E>
     * @param <T>
     * @return
     */
    private <E extends BaseReq, T extends BaseResp> T doRealDealGetBean(E request, Class<T> cla, InterEnum interName) {
        return doHttps(request, C.EMPTY_STR, interName, cla);
    }

    /**
     * 调用对应的接口,返回bean对象
     *
     * @param request
     * @param cla
     * @param interName
     * @param <E>
     * @param <T>
     * @return
     */
    private <E extends BaseReq, T extends BaseResp> T doRealDealGetBean(E request, Class<T> cla, String sslPwd, InterEnum interName) {
        return doHttps(request, sslPwd, interName, cla);
    }

    /**
     * 调用对应的接口,返回Map<String, String>
     *
     * @param request
     * @param interName
     * @param <E>
     * @param <T>
     * @return
     */
    private <E extends BaseReq, T extends BaseResp> Map<String, String> doRealDealGetMap(E request, InterEnum interName) {
        return WXPayUtil.xmlToMap(doHttps(request, C.EMPTY_STR, interName));
    }

    /**
     * 调用接口获取xml返回
     *
     * @param request
     * @param interName
     * @param <E>
     * @param <T>
     * @return
     */
    private <E extends BaseReq, T extends BaseResp> String doHttps(E request, String sslPwd, InterEnum interName) {
        //组装头信息
        try {
            PropertyPreFilters filters = new PropertyPreFilters();
            PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
            String[] excludeProperties = {"channelMerchantInfoEntity"};
            excludefilter.addExcludes(excludeProperties);
            JSONObject reqObj = JSON.parseObject(JSON.toJSONString(request, excludefilter));
            //商户平台key
            String key = weixinGlobalConfig.getApiKey();
            String certPath = "";
            if(null != request.getChannelMerchantInfoEntity()){
                //兼容使用渠道商户信息表配置逻辑，优先使用表配置的key
                key = request.getChannelMerchantInfoEntity().getApiKey();
                certPath = request.getChannelMerchantInfoEntity().getCertPath();
            }
            //1.进行签名
            WechatSignUtil.sign(reqObj, key);
            //获取接口地址
            String url = takeInterUrl(interName);
            //2.调用对应的接口
            String respXml = httpsPost(url, XmlUtil.toXml(reqObj), sslPwd, interName, certPath);
            BaseResp baseResp = XmlUtil.toBean(respXml, BaseResp.class);
            if(TradeStatusEnum.SUCCESS.name().equals(baseResp.getReturnCode())){
                //验证签名
                if (!WechatSignUtil.verifySign(respXml, key)) {
                    throw new SystemException(ExceptionEnum.E10005);
                }
            }
            return respXml;
        } catch (Exception e) {
            LogUtil.error(logger, e, "微信接口调用失败");
            if (e instanceof SystemException) {
                throw e;
            } else {
                //超时固定编码，请勿改动错误编码
                throw new SystemException(ExceptionEnum.TIME_OUT);
            }
        }
    }


    /**
     * 调用接口获取xml返回
     *
     * @param request
     * @param interName
     * @param <E>
     * @param <T>
     * @return
     */
    private <E extends BaseReq, T extends BaseResp> T doHttps(E request, String sslPwd, InterEnum interName, Class<T> cla) {
        //组装头信息
        try {
            PropertyPreFilters filters = new PropertyPreFilters();
            PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
            String[] excludeProperties = {"channelMerchantInfoEntity"};
            excludefilter.addExcludes(excludeProperties);
            JSONObject reqObj = JSON.parseObject(JSON.toJSONString(request, excludefilter));
            //商户平台key
            String key = weixinGlobalConfig.getApiKey();
            String certPath = "";
            if(null != request.getChannelMerchantInfoEntity()){
                //兼容使用渠道商户信息表配置逻辑，优先使用表配置的key
                key = request.getChannelMerchantInfoEntity().getApiKey();
                certPath = request.getChannelMerchantInfoEntity().getCertPath();
            }
            //1.进行签名
            WechatSignUtil.sign(reqObj, key);
            //获取接口地址
            String url = takeInterUrl(interName);
            //2.调用对应的接口
            String requestXml = XmlUtil.toXmlNonNull(JSON.parseObject(reqObj.toJSONString(), request.getClass()));
            String respXml = httpsPost(url, requestXml, sslPwd, interName, certPath);
            T baseResp = XmlUtil.toBean(respXml, cla);
            if(TradeStatusEnum.SUCCESS.name().equals(baseResp.getReturnCode())){
                //验证签名
                if (!WechatSignUtil.verifySign(respXml, key)) {
                    throw new SystemException(ExceptionEnum.E10005);
                }
            }
            if (baseResp instanceof PrepayResp){
                PrepayResp resp = (PrepayResp) baseResp;
                resp.setReqXml(requestXml);
                resp.setRespXml(respXml);
                return (T) resp;
            }
            return baseResp;
        } catch (Exception e) {
            LogUtil.error(logger, e, "微信接口调用失败");
            if (e instanceof SystemException) {
                throw e;
            } else {
                //超时固定编码，请勿改动错误编码
                throw new SystemException(ExceptionEnum.TIME_OUT);
            }
        }
    }

    /**
     * 获取接口url
     *
     * @param interEnum
     * @return
     */
    private String takeInterUrl(InterEnum interEnum) {
        switch (interEnum) {
            case PREPAY:
                return weixinGlobalConfig.getPrepayUrl();
            case PAY_QUERY:
                return weixinGlobalConfig.getPayQueryUrl();
            case CLOSE_ORDER:
                return weixinGlobalConfig.getCloseOrderUrl();
            case APPLY_REFUND:
                return weixinGlobalConfig.getApplyRefundUrl();
            case QUERY_REFUND:
                return weixinGlobalConfig.getQueryRefundUrl();
            case DECLARE_CUSTOMS:
                return weixinGlobalConfig.getDeclareCustomsUrl();
            case DECLARE_CUSTOMS_QUERY:
                return weixinGlobalConfig.getDeclareCustomsQryUrl();
            case DECLARE_CUSTOMS_RESEND:
                return weixinGlobalConfig.getDeclareRetryUrl();
            default:
                return null;
        }
    }

    /**
     * 发送https请求
     *
     * @param url
     * @param msg
     * @param interEnum
     * @param certPath
     * @return
     */
    public String httpsPost(String url, String msg, String sslPwd, InterEnum interEnum, String certPath) {
        //微信报关日志外层有打印，不再单独做脱敏处理
        if(!InterEnum.DECLARE_CUSTOMS.equals(interEnum)) {
            LogUtil.info(logger, "请求微信{0}接口入参：{1}", interEnum.getInterName(), msg);
        }
        SSLConnectionSocketFactory sslf = null;
        String resp = null;
        //只有退款才需要证书
        if (InterEnum.APPLY_REFUND == interEnum) {
            sslf = getSSLcontext(sslPwd, certPath);
        }
        CloseableHttpClient httpclient = getHttpclient(sslf);
        CloseableHttpResponse response = null;
        HttpPost httppost = new HttpPost(url);
        try {
            InputStream inputStream = new ByteArrayInputStream(msg.getBytes(StandardCharsets.UTF_8));
            InputStreamEntity reqEntity = new InputStreamEntity(inputStream, -1, ContentType.APPLICATION_XML);
            reqEntity.setChunked(true);
            httppost.setEntity(reqEntity);
            // 设置请求和传输超时时间
            RequestConfig config = RequestConfig.custom().setSocketTimeout(REQUEST_TIME).setConnectTimeout(REQUEST_TIME).build();
            httppost.setConfig(config);
            long start = System.currentTimeMillis();
            response = httpclient.execute(httppost);
            if (response == null || response.getStatusLine().getStatusCode() != 200) {
                LogUtil.error(logger, "请求微信接口异常 返回:{0}", response);
                throw new SystemException(ExceptionEnum.TIME_OUT);
            }

            long takeTime = System.currentTimeMillis() - start;
            resp = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
            LogUtil.info(logger, "请求微信{0}接口耗时：{1}，出参：\n{2} ", interEnum.getInterName(), takeTime, resp);
        } catch (IOException e) {
            LogUtil.error(logger, e, "请求微信接口异常");
            throw new SystemException(ExceptionEnum.TIME_OUT);
        } finally {
            try {
                httpclient.close();
                if (null != response) {
                    response.close();
                    EntityUtils.consumeQuietly(response.getEntity());
                }
                httppost.abort();
            } catch (Exception e) {
                LogUtil.error(logger, e, "微信https关闭异常");
            }
        }
        return resp;
    }

    private static CloseableHttpClient getHttpclient(SSLConnectionSocketFactory sslsf) {
        HttpClientBuilder builder = HttpClientBuilder.create();
        if (null != sslsf) {
            builder.setSSLSocketFactory(sslsf);
        }
        return builder.build();
    }

    private SSLConnectionSocketFactory getSSLcontext(String sslPwd, String certPath) {
        SSLConnectionSocketFactory sslsf = sslsfMap.get(certPath);
        if(sslsf != null){
            return sslsf;
        }
        FileInputStream keystoreInstream = null;
        try {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");

            //String currentPath = Thread.currentThread().getContextClassLoader().getResource(weixinGlobalConfig.getCertPath()).getPath();
            String currentPath = weixinGlobalConfig.getCertPath();
            if(!StringUtils.isEmpty(certPath)){
                currentPath = certPath;
            }
            LogUtil.info(logger, "证书路径：{0} ", currentPath);
            // 加载keyStore channel.pfx
            keystoreInstream = new FileInputStream(new File(currentPath));
            keyStore.load(keystoreInstream, sslPwd.toCharArray());

            X509TrustManager tm = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
                @Override
                public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            String alg = KeyManagerFactory.getDefaultAlgorithm();
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(alg);
            keyManagerFactory.init(keyStore, sslPwd.toCharArray());
            KeyManager[] kms = keyManagerFactory.getKeyManagers();

            SSLContext sslcontext = SSLContext.getInstance("SSL");
            sslcontext.init(kms, new TrustManager[]{tm}, null);
            sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"}, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            sslsfMap.put(certPath, sslsf);
        } catch (Exception e) {
            LogUtil.error(logger, e,"获取SSLContext异常");
            throw new SystemException(ExceptionEnum.E10003);
        } finally {
            try {
                keystoreInstream.close();
            } catch (IOException e) {
                LogUtil.error(logger, e,"keystoreInstream close error");
            }
        }
        return sslsf;

    }

    /**
     * h5场景，固定格式
     * @param scenceCode
     * @param sceneName
     * @return
     */
    public static String getH5Scence(String scenceCode, String sceneName) {
        return "{\"h5_info\":{\"type\":\"Wap\",\"wap_url\":\""+scenceCode+"\",\"wap_name\":\""+sceneName+"\"}}";
    }

    /**
     * 公共请求头
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class BaseReq implements Serializable {

        private static final long serialVersionUID = 7327708939117086713L;

        @JacksonXmlProperty(localName = "appid")
        @JSONField(name = "appid")
        private String appId;

        @JacksonXmlProperty(localName = "mch_id")
        @JSONField(name = "mch_id")
        private String mchId;

        @JacksonXmlProperty(localName = "nonce_str")
        @JSONField(name = "nonce_str")
        private String nonceStr;

        @JacksonXmlProperty(localName = "sign")
        @JSONField(name = "sign")
        private String sign;

        private ChannelMerchantInfoEntity channelMerchantInfoEntity;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 公共应答头
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class BaseResp implements Serializable {

        private static final long serialVersionUID = 2533494895245990422L;

        @JacksonXmlProperty(localName = "return_code")
        @JSONField(name = "return_code")
        private String returnCode;

        @JacksonXmlProperty(localName = "return_msg")
        @JSONField(name = "return_msg")
        private String returnMsg;

        @JacksonXmlProperty(localName = "appid")
        @JSONField(name = "appid")
        private String appId;

        @JacksonXmlProperty(localName = "mch_id")
        @JSONField(name = "mch_id")
        private String mchId;

        @JacksonXmlProperty(localName = "nonce_str")
        @JSONField(name = "nonce_str")
        private String nonceStr;

        @JacksonXmlProperty(localName = "result_code")
        @JSONField(name = "result_code")
        private String resultCode;

        @JacksonXmlProperty(localName = "err_code")
        @JSONField(name = "err_code")
        private String errCode;

        @JacksonXmlProperty(localName = "err_code_des")
        @JSONField(name = "err_code_des")
        private String errCodeDes;

        @JacksonXmlProperty(localName = "sign")
        @JSONField(name = "sign")
        private String sign;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 预支付请求
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class PrepayReq extends BaseReq {

        private static final long serialVersionUID = 6695687752300450727L;
        @JacksonXmlProperty(localName = "body")
        @JSONField(name = "body")
        private String body;

        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        @JacksonXmlProperty(localName = "total_fee")
        @JSONField(name = "total_fee")
        private Integer totalFee;

        @JacksonXmlProperty(localName = "spbill_create_ip")
        @JSONField(name = "spbill_create_ip")
        private String spbillCreateIp;

        @JacksonXmlProperty(localName = "notify_url")
        @JSONField(name = "notify_url")
        private String notifyUrl;

        @JacksonXmlProperty(localName = "trade_type")
        @JSONField(name = "trade_type")
        private String tradeType;

        @JacksonXmlProperty(localName = "time_start")
        @JSONField(name = "time_start")
        private String timeStart;

        @JacksonXmlProperty(localName = "time_expire")
        @JSONField(name = "time_expire")
        private String timeExpire;

        @JacksonXmlProperty(localName = "openid")
        @JSONField(name = "openid")
        private String openId;

        @JacksonXmlProperty(localName = "scene_info")
        @JSONField(name = "sceneInfo")
        private String sceneInfo;

        @JacksonXmlProperty(localName = "attach")
        @JSONField(name = "attach")
        private String attach;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 预支付返回
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class PrepayResp extends BaseResp {

        private static final long serialVersionUID = 30370423130501357L;
        @JacksonXmlProperty(localName = "trade_type")
        @JSONField(name = "trade_type")
        private String tradeType;

        @JacksonXmlProperty(localName = "prepay_id")
        @JSONField(name = "prepay_id")
        private String prepayId;

        @JacksonXmlProperty(localName = "mweb_url")
        @JSONField(name = "mweb_url")
        private String mwebUrl;

        private String reqXml;

        private String respXml;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 支付状态查询请求
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class PayQueryReq extends BaseReq {

        private static final long serialVersionUID = 6495622338150619801L;
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outOrderNo;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }

    }

    /**
     * 支付状态查询返回
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class PayQueryResp extends BaseResp {

        private static final long serialVersionUID = -6967060153778843023L;
        @JacksonXmlProperty(localName = "openid")
        @JSONField(name = "openid")
        private String openId;

        @JacksonXmlProperty(localName = "is_subscribe")
        @JSONField(name = "is_subscribe")
        private String isSubscribe;

        @JacksonXmlProperty(localName = "trade_type")
        @JSONField(name = "trade_type")
        private String tradeType;

        @JacksonXmlProperty(localName = "trade_state")
        @JSONField(name = "trade_state")
        private String tradeState;

        @JacksonXmlProperty(localName = "bank_type")
        @JSONField(name = "bank_type")
        private String bankType;

        @JacksonXmlProperty(localName = "fee_type")
        @JSONField(name = "fee_type")
        private String feeType;

        @JacksonXmlProperty(localName = "total_fee")
        @JSONField(name = "total_fee")
        private Integer totalFee;

        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        @JacksonXmlProperty(localName = "attach")
        @JSONField(name = "attach")
        private String attach;

        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        @JacksonXmlProperty(localName = "time_end")
        @JSONField(name = "time_end")
        private String timeEnd;

        @JacksonXmlProperty(localName = "trade_state_desc")
        @JSONField(name = "trade_state_desc")
        private String tradeStateDesc;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }

    }

    /**
     * 申请退款请求
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class ApplyRefundReq extends BaseReq {

        private static final long serialVersionUID = 7160825858699036414L;
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        @JacksonXmlProperty(localName = "total_fee")
        @JSONField(name = "total_fee")
        private Integer totalFee;

        @JacksonXmlProperty(localName = "refund_fee")
        @JSONField(name = "refund_fee")
        private Integer refundFee;

        /**
         * outRefundNo
         * 商户退款单号
         */
        @JacksonXmlProperty(localName = "out_refund_no")
        @JSONField(name = "out_refund_no")
        private String outRefundNo;

        @JacksonXmlProperty(localName = "notify_url")
        @JSONField(name = "notify_url")
        private String notifyUrl;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }

    }

    /**
     * 申请退款返回
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class ApplyRefundResp extends BaseResp {

        private static final long serialVersionUID = -3835575508759531276L;
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        @JacksonXmlProperty(localName = "out_refund_no")
        @JSONField(name = "out_refund_no")
        private String outRefundNo;

        @JacksonXmlProperty(localName = "refund_id")
        @JSONField(name = "refund_id")
        private String refundId;

        @JacksonXmlProperty(localName = "refund_fee")
        @JSONField(name = "refund_fee")
        private Integer refundFee;

        @JacksonXmlProperty(localName = "settlement_refund_fee")
        @JSONField(name = "settlement_refund_fee")
        private Integer settlementRefundFee;

        @JacksonXmlProperty(localName = "total_fee")
        @JSONField(name = "total_fee")
        private Integer totalFee;

        @JacksonXmlProperty(localName = "settlement_total_fee")
        @JSONField(name = "settlement_total_fee")
        private Integer settlementTotalFee;

        @JacksonXmlProperty(localName = "fee_type")
        @JSONField(name = "fee_type")
        private String feeType;

        @JacksonXmlProperty(localName = "cash_fee")
        @JSONField(name = "cash_fee")
        private Integer cashFee;

        @JacksonXmlProperty(localName = "cash_fee_type")
        @JSONField(name = "cash_fee_type")
        private String cashFeeType;

        @JacksonXmlProperty(localName = "cash_refund_fee")
        @JSONField(name = "cash_refund_fee")
        private Integer cashRefundFee;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }

    }

    /**
     * 关单请求
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class CloseOrderReq extends BaseReq {

        private static final long serialVersionUID = -2925449894532386407L;
        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 关单应答
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class CloseOrderResp extends BaseResp {

        private static final long serialVersionUID = 5548884279967468523L;
        @JacksonXmlProperty(localName = "result_msg")
        @JSONField(name = "result_msg")
        private String resultMsg;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 退款查询请求
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class QueryRefundReq extends BaseReq {

        private static final long serialVersionUID = 7584154449734495040L;
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        @JacksonXmlProperty(localName = "out_refund_no")
        @JSONField(name = "out_refund_no")
        private String outRefundNo;

        @JacksonXmlProperty(localName = "refund_id")
        @JSONField(name = "refund_id")
        private String refundId;

        @JacksonXmlProperty(localName = "offset")
        @JSONField(name = "offset")
        private Integer offset;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 退款查询应答
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class QueryRefundResp extends BaseResp {

        private static final long serialVersionUID = -4610832415701396952L;
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId; //微信订单号

        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;//商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*@ ，且在同一个商户号下唯一

        @JacksonXmlProperty(localName = "total_refund_count")
        @JSONField(name = "total_refund_count")
        private Integer totalRefundCount;

        @JacksonXmlProperty(localName = "total_fee")
        @JSONField(name = "total_fee")
        private Integer totalFee;

        @JacksonXmlProperty(localName = "fee_type")
        @JSONField(name = "fee_type")
        private String feeType;

        @JacksonXmlProperty(localName = "cash_fee")
        @JSONField(name = "cash_fee")
        private Integer cashFee;

        @JacksonXmlProperty(localName = "cash_fee_type")
        @JSONField(name = "cash_fee_type")
        private String cashFeeType;

        @JacksonXmlProperty(localName = "settlement_total_fee")
        @JSONField(name = "settlement_total_fee")
        private Integer settlementTotalFee;

        @JacksonXmlProperty(localName = "refund_count")
        @JSONField(name = "refund_count")
        private Integer refundCount;

        @JacksonXmlProperty(localName = "refund_account_0")
        @JSONField(name = "refund_account_0")
        private String refundAccount;

        @JacksonXmlProperty(localName = "refund_channel_0")
        @JSONField(name = "refund_channel_0")
        private String refundChannel;

        @JacksonXmlProperty(localName = "refund_fee")
        @JSONField(name = "refund_fee")
        private Integer refundFee;

        @JacksonXmlProperty(localName = "refund_id_0")
        @JSONField(name = "refund_id_0")
        private String refundId;

        @JacksonXmlProperty(localName = "refund_recv_accout_0")
        @JSONField(name = "refund_recv_accout_0")
        private String refundRecvAccout;

        @JacksonXmlProperty(localName = "refund_status_0")
        @JSONField(name = "refund_status_0")
        private String refundStatus;

        @JacksonXmlProperty(localName = "refund_success_time_0")
        @JSONField(name = "refund_success_time_0")
        private String refundSuccessTime;

      //  private List<RefundInfoDto> refundInfos;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 退款明细
     */
    @Getter
    @Setter
    public static class RefundInfoDto implements Serializable {

        private static final long serialVersionUID = 5652673093521419702L;
        private String outRefundNo;

        private String refundId;

        private String refundChannel;

        private Integer refundFee;

        private String refundStatus;

        private String refundAccount;

        private String refundRecvAccount;

        private String refundSuccessTime;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 微信报关请求
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class DeclareCustomsReq extends BaseReq {

        private static final long serialVersionUID = -4249864430281474819L;
        /*商户订单号*/
        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        /*微信支付订单号*/
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        /*海关*/
        @JacksonXmlProperty(localName = "customs")
        @JSONField(name = "customs")
        private String customs;

        /*商户海关备案号*/
        @JacksonXmlProperty(localName = "mch_customs_no")
        @JSONField(name = "mch_customs_no")
        private String mchCustomsNo;

        /*关税*/
        @JacksonXmlProperty(localName = "duty")
        @JSONField(name = "duty")
        private int duty;

        /*报关类型*/
        @JacksonXmlProperty(localName = "action_type")
        @JSONField(name = "action_type")
        private String actionType;

        /*商户子订单号*/
        @JacksonXmlProperty(localName = "sub_order_no")
        @JSONField(name = "sub_order_no")
        private String subOrderNo;

        /*币种*/
        @JacksonXmlProperty(localName = "fee_type")
        @JSONField(name = "fee_type")
        private String feeType;

        /*应付金额*/
        @JacksonXmlProperty(localName = "order_fee")
        @JSONField(name = "order_fee")
        private int orderFee;

        /*物流费*/
        @JacksonXmlProperty(localName = "transport_fee")
        @JSONField(name = "transport_fee")
        private int transportFee;

        /*商品价格*/
        @JacksonXmlProperty(localName = "product_fee")
        @JSONField(name = "product_fee")
        private int productFee;

        /*证件类型*/
        @JacksonXmlProperty(localName = "cert_type")
        @JSONField(name = "cert_type")
        private String certType;

        /*证件号码*/
        @JacksonXmlProperty(localName = "cert_id")
        @JSONField(name = "cert_id")
        private String certId;

        /*姓名*/
        @JacksonXmlProperty(localName = "name")
        @JSONField(name = "name")
        private String name;

        @Override
        public String toString() {
            return (new ReflectionToStringBuilder(this, ToStringStyle.JSON_STYLE) {
                @Override
                protected boolean accept(Field f) {
                    return super.accept(f) && !f.getName().equals("name") && !f.getName().equals("certId");
                }
            }).toString();
        }
    }

    /**
     * 微信报关响应
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class DeclareCustomsResp extends BaseResp {

        private static final long serialVersionUID = 3500577487972540373L;
        /*返回状态吗*/
        @JacksonXmlProperty(localName = "return_code")
        @JSONField(name = "return_code")
        private String returnCode;

        /*返回信息*/
        @JacksonXmlProperty(localName = "return_msg")
        @JSONField(name = "return_msg")
        private String returnMsg;

        /*签名类型*/
        @JacksonXmlProperty(localName = "sign_type")
        @JSONField(name = "sign_type")
        private String signType;

        /*签名*/
        @JacksonXmlProperty(localName = "sign")
        @JSONField(name = "sign")
        private String sign;

        /*公众账号类型*/
        @JacksonXmlProperty(localName = "appid")
        @JSONField(name = "appid")
        private String appid;

        /*商户号*/
        @JacksonXmlProperty(localName = "mch_id")
        @JSONField(name = "mch_id")
        private String mchId;

        /*业务结果*/
        @JacksonXmlProperty(localName = "result_code")
        @JSONField(name = "result_code")
        private String resultCode;

        /*错误代码*/
        @JacksonXmlProperty(localName = "err_code")
        @JSONField(name = "err_code")
        private String errCode;

        /*错误代码描述*/
        @JacksonXmlProperty(localName = "err_code_des")
        @JSONField(name = "err_code_des")
        private String errCodeDes;

        /*状态码*/
        @JacksonXmlProperty(localName = "state")
        @JSONField(name = "state")
        private String state;

        /*微信支付订单号*/
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        /*商户订单号*/
        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        /*商户子订单号*/
        @JacksonXmlProperty(localName = "sub_order_no")
        @JSONField(name = "sub_order_no")
        private String subOrderNo;

        /*微信子订单号*/
        @JacksonXmlProperty(localName = "sub_order_id")
        @JSONField(name = "sub_order_id")
        private String subOrderId;

        /*最后更新时间*/
        @JacksonXmlProperty(localName = "modify_time")
        @JSONField(name = "modify_time")
        private String modifyTime;

        /*订购人和支付人身份信息检验结果*/
        @JacksonXmlProperty(localName = "cert_check_result")
        @JSONField(name = "cert_check_result")
        private String certCheckResult;

        /*验核机构*/
        @JacksonXmlProperty(localName = "verify_department")
        @JSONField(name = "verify_department")
        private String verifyDepartment;

        /*验核机构交易流水号*/
        @JacksonXmlProperty(localName = "verify_department_trade_id")
        @JSONField(name = "verify_department_trade_id")
        private String verifyDepartmentTradeId;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 微信报关查询请求
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class DeclareCustomsQryReq extends BaseReq {

        private static final long serialVersionUID = 4475407421347394320L;
        /*签名类型*/
        @JacksonXmlProperty(localName = "sign_type")
        @JSONField(name = "sign_type")
        private String signType;

        /*签名*/
        @JacksonXmlProperty(localName = "sign")
        @JSONField(name = "sign")
        private String sign;

        /*商户号*/
        @JacksonXmlProperty(localName = "mch_id")
        @JSONField(name = "mch_id")
        private String mchId;

        /*商户订单号*/
        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        /*微信支付订单号*/
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        /*商户子订单号*/
        @JacksonXmlProperty(localName = "sub_order_no")
        @JSONField(name = "sub_order_no")
        private String subOrderNo;

        /*微信子订单号*/
        @JacksonXmlProperty(localName = "sub_order_id")
        @JSONField(name = "sub_order_id")
        private String subOrderId;

        /*海关*/
        @JacksonXmlProperty(localName = "customs")
        @JSONField(name = "customs")
        private String customs;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 微信报关查询响应
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class DeclareCustomsQryResp extends BaseResp {

        private static final long serialVersionUID = 3111522811360026746L;
        /*返回状态码*/
        @JacksonXmlProperty(localName = "return_code")
        @JSONField(name = "return_code")
        private String returnCode;

        /*返回信息*/
        @JacksonXmlProperty(localName = "return_msg")
        @JSONField(name = "return_msg")
        private String returnMsg;

        /*签名*/
        @JacksonXmlProperty(localName = "sign")
        @JSONField(name = "sign")
        private String sign;


        /*商户号*/
        @JacksonXmlProperty(localName = "mch_id")
        @JSONField(name = "mch_id")
        private String mchId;

        /*业务结果*/
        @JacksonXmlProperty(localName = "result_code")
        @JSONField(name = "result_code")
        private String resultCode;

        /*错误代码*/
        @JacksonXmlProperty(localName = "err_code")
        @JSONField(name = "err_code")
        private String errCode;

        /*错误代码描述*/
        @JacksonXmlProperty(localName = "err_code_des")
        @JSONField(name = "err_code_des")
        private String errCodeDesc;

        /*微信支付单号*/
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        /*笔数*/
        @JacksonXmlProperty(localName = "count")
        @JSONField(name = "count")
        private int count;


        /*报关子单结果集list*/
        private List<DeclareCustomsQryInfo> resultList;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }

    }

    @Getter
    @Setter
    public static class DeclareCustomsQryInfo implements Serializable{

        private static final long serialVersionUID = -7895998608709476637L;
        /* 第几笔 */
        private Integer index;

        /*商户子订单号*/
        private String subOrderNo;

        /*微信子订单号*/
        private String subOrderId;

        /*商户海关备案号*/
        private String mchCustomsNo;

        /*海关*/
        private String customs;

        /*币种*/
        private String feeType;

        /*应付金额*/
        private int orderFee;

        /*关税*/
        private int duty;

        /*物流费*/
        private int transportFee;

        /*商品价格*/
        private int productFee;

        /*状态码*/
        private String state;

        /*申报结果说明*/
        private String explanation;

        /*最后更新时间*/
        private String modifyTime;

        /*订购人和支付人身份信息校验结果*/
        private String certCheckResult;

        /*验核机构*/
        private String verifyDepartment;

        /*验核机构流水号*/
        private String verifyDepartmentTradeId;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }

    }

    /**
     * 微信报关重推请求
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class DeclareCustomsResendReq extends DeclareCustomsQryReq {
        private static final long serialVersionUID = 6839620290314192418L;
        /*商户海关备案号*/
        @JacksonXmlProperty(localName = "mch_customs_no")
        @JSONField(name = "mch_customs_no")
        private String mchCustomsNo;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    /**
     * 微信报关重推响应
     */
    @Getter
    @Setter
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JacksonXmlRootElement(localName = "xml")
    public static class DeclareCustomsResendResp extends BaseResp {

        private static final long serialVersionUID = -1644877997248611917L;
        /*返回状态码*/
        @JacksonXmlProperty(localName = "return_code")
        @JSONField(name = "return_code")
        private String returnCode;

        /*返回信息*/
        @JacksonXmlProperty(localName = "return_msg")
        @JSONField(name = "return_msg")
        private String returnMsg;

        /*签名类型*/
        @JacksonXmlProperty(localName = "sign_type")
        @JSONField(name = "sign_type")
        private String signType;

        /*签名*/
        @JacksonXmlProperty(localName = "sign")
        @JSONField(name = "sign")
        private String sign;

        /*公众账号id*/
        @JacksonXmlProperty(localName = "appid")
        @JSONField(name = "appid")
        private String appid;

        /*商户号*/
        @JacksonXmlProperty(localName = "mch_id")
        @JSONField(name = "mch_id")
        private String mchId;

        /*业务结果*/
        @JacksonXmlProperty(localName = "result_code")
        @JSONField(name = "result_code")
        private String resultCode;

        /*错误代码*/
        @JacksonXmlProperty(localName = "err_code")
        @JSONField(name = "err_code")
        private String errCode;

        /*错误代码描述*/
        @JacksonXmlProperty(localName = "err_code_des")
        @JSONField(name = "err_code_des")
        private String errCodeDesc;

        /*状态码*/
        @JacksonXmlProperty(localName = "state")
        @JSONField(name = "state")
        private String state;

        /*微信支付订单号*/
        @JacksonXmlProperty(localName = "transaction_id")
        @JSONField(name = "transaction_id")
        private String transactionId;

        /*商户订单号*/
        @JacksonXmlProperty(localName = "out_trade_no")
        @JSONField(name = "out_trade_no")
        private String outTradeNo;

        /*商户子订单号*/
        @JacksonXmlProperty(localName = "sub_order_no")
        @JSONField(name = "sub_order_no")
        private String subOrderNo;

        /*微信子订单号*/
        @JacksonXmlProperty(localName = "sub_order_id")
        @JSONField(name = "sub_order_id")
        private String subOrderId;

        /*最后更新时间*/
        @JacksonXmlProperty(localName = "modify_time")
        @JSONField(name = "modify_time")
        private String modifyTime;

        /*申报结果说明*/
        @JacksonXmlProperty(localName = "explanation")
        @JSONField(name = "explanation")
        private String explanation;


        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
        }
    }

    public static void main(String[] args){
        LogUtil.info(logger, "请求微信{0}接口入参：{1}", "name", "value");
    }
}
